#define DEBUG

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectInput;

using System.Runtime.InteropServices;

using TTDotNet.Util;
using TTDotNet.Engine.Create.Tools;
using TTDotNet.Engine.Companies;
using TTDotNet.Debug;
using TTDotNet.Engine.GUI;
using TTDotNet.Engine.GUI.Windows;
using TTDotNet.Engine.Files;
using TTDotNet.Engine.Industries;
using TTDotNet.Engine.Networks;
using TTDotNet.Engine.Stations;
using TTDotNet.Engine.Terrain;
using TTDotNet.Engine.ThreeDEngine;
using TTDotNet.Engine.Vehicles;

namespace TTDotNet.Engine
{
    public class Game : System.Windows.Forms.Form
    {
        #region Global Vars

        private Coordinate oldCursorLocation;
        private Coordinate newCursorLocation;

        public static GameLogger logger;
        public static bool debug = true;

        private Vehicle myVehc;
        private Random rng = new Random();

        private PresentParameters pres;

        public const float heightScale = 4.0f;

        public static GUIManager newGUI;

        public Texture renderedTo;
        public Surface surface;
        public Surface oldRenderTarget;

        public static Microsoft.DirectX.Direct3D.Device device;

        public static Microsoft.DirectX.DirectInput.Device keyb = null;
        private Microsoft.DirectX.DirectInput.Device mouse = null;
        private Microsoft.DirectX.DirectInput.Device wheel = null;
        public static JoystickState wheelState = new JoystickState();

        private bool quitting = false;

        private MouseState state;
        private byte[] mouseButtons;

        public static bool paused = false;

        private Coordinate hoverTile;

        private Stopwatch loopTimer;

        int r = 0;
        int g = 0;
        int b = 0;
        bool redDone = false;
        bool greenDone = false;
        bool blueDone = false;

        public static TexLoader texLoader;

        //public static RoadNetwork roadNetwork;
        public static LandscapingTool landscaper;

        public static MeshManager meshManager;
        public static TextureCacher textureCacher;
        public static Sprite guiSprite;
        public static Microsoft.DirectX.Direct3D.Font arial14;

        public static Toolbox toolbox;
        public static Stopwatch texTime;

        public static World gameWorld;

        public static AJCamera myCamera;
        public AJCamera vehcCam;

        private Vehicle selected;

        private List<Keys> keysPressed;
        public static int playerNumber;

        private MouseEventArgs lastMouseEventArgs;

        private bool onTheGui;
        private int frames = 0;
        public static Graphics windowGraphic;

        public int mouseMoves = 0;

        #endregion

        public Game(string arg) : base()
        {
            texTime = new Stopwatch();
            texTime.Start();

            if(debug) {
                logger = new GameLogger();
                logger.WriteLine("Created new GameLog at " + DateTime.Now + " - " + Environment.UserName);
            }

            Show();
            windowGraphic = this.CreateGraphics();

            if (debug) logger.WriteLine("\r\nInitializeComponent Begins:");
            InitializeComponent();
            
            keysPressed = new List<Keys>();
            pres = new PresentParameters();

            if (debug) logger.WriteLine("\r\nGraphics Initialization Begins:");
            InitializeGraphics();

            textureCacher = new TextureCacher();

            if (debug) logger.WriteLine("\r\nDevice Initialization Begins:");
            InitializeDevice();

            if (debug) logger.WriteLine("\r\nToolbox Creation Begins:");
            toolbox = new Toolbox(this);

            texTime.Stop();
            hoverTile = new Coordinate(0, 0);

            lastMouseEventArgs = new MouseEventArgs(MouseButtons.None, 0, 0, 0, 0);

            meshManager = new MeshManager();

            oldCursorLocation = new Coordinate(0, 0);
            newCursorLocation = new Coordinate(0, 0);
            
            myCamera = new AJCamera(this.Width, this.Height, false);
            
            this.KeyPress += new KeyPressEventHandler(Game_KeyPress);
            this.KeyDown += new KeyEventHandler(Game_KeyDown);
            this.KeyUp += new KeyEventHandler(Game_KeyUp);
            this.MouseDown += new MouseEventHandler(myMouseDown);
            this.MouseUp += new MouseEventHandler(myMouseUp);
            this.MouseMove += new MouseEventHandler(mouseMove);
            this.MouseWheel += new MouseEventHandler(myMouseWheel);

            device.DeviceReset += new EventHandler(device_DeviceReset);
            device.DeviceResizing += new System.ComponentModel.CancelEventHandler(device_DeviceResizing);
            

            texTime.Start();

            if (debug) logger.WriteLine("\r\nMouse Acquisition Begins:");
            InitializeMouse();

            if (debug) logger.WriteLine("\r\nKeyboard Acquisition Begins:");
            InitializeKeyboard();

            if (debug) logger.WriteLine("\r\nGUI Initialization Begins:");
            InitializeGUI();
            
            if (debug) logger.WriteLine("\r\nTexture Loader Initialization Begins:");
            texLoader = new TexLoader();
            

            loopTimer = new Stopwatch();
            loopTimer.Start();

            if (debug) logger.WriteLine("\r\nWorld Initialization Begins:");
            InitializeGame(Int32.Parse(arg));

            if (debug) logger.WriteLine("\r\nRender/Engine Loop Begins:");
            StartLoop();

            logger.CloseAndDelete();

            //System.Windows.Forms.MessageBox.Show("Took " + texTime.ElapsedMilliseconds + " millis");
        }

        void device_DeviceResizing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            //e.Cancel = true;
        }

        private void InitializeWheel()
        {
            foreach (DeviceInstance instance in Microsoft.DirectX.DirectInput.Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly))
            {
                // Create the device.  Just pick the first one
                wheel = new Microsoft.DirectX.DirectInput.Device(instance.InstanceGuid);
                break;
            }
        }

        void Game_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (newGUI.KeyBoardHandler(keysPressed, e.KeyChar, Convert.ToInt32(e.KeyChar)))
            {
                onTheGui = true;
            }
        }

        void Game_KeyUp(object sender, KeyEventArgs e)
        {
            keysPressed.Remove(e.KeyCode);

            if (keysPressed.Count == 0)
            {
                onTheGui = false;
            }
        }

        void Game_KeyDown(object sender, KeyEventArgs e)
        {
            if (!keysPressed.Contains(e.KeyCode))
            {
                keysPressed.Add(e.KeyCode);
            }

            if (e.KeyCode != Keys.Back)
            {
                if (newGUI.KeyBoardHandler(keysPressed, char.MinValue, e.KeyValue))
                {
                    onTheGui = true;
                }
            }
        }

        void device_DeviceReset(object sender, EventArgs e)
        {
            try
            {
                //device.Reset(pres);
                gameWorld.Scene.ReloadResources();
                //gameWorld.setupGrid(device, myCamera);
                myCamera.ChangeAspectRatio(this.Width, this.Height);
            }
            catch (DeviceLostException)
            {
                Text = "Device is lost " + DateTime.Now.Second;
            }
        }

        private void StartLoop()
        {
            try
            {
                System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);
                if (debug) logger.WriteLine("Render/Engine Loop Started Successfully!...");
            }
            catch (Exception e)
            {
                CloseOnException(e);
            }
        }

        private void OnApplicationIdle(object sender, EventArgs e)
        {
            while (AppStillIdle && !quitting)
            {
                //Console.WriteLine(DateTime.Now.Millisecond);

                try
                {
                    if (!(this.WindowState == FormWindowState.Minimized))
                    {
                        Render();
                    }
                }
                catch (Exception f)
                {
                    GameLogger crashReport = new GameLogger(f);
                    Environment.Exit(1);
                }
            }
        }

        private bool AppStillIdle
        {
            get
            {
                try
                {
                    NativeMethods.Message msg;
                    return !NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);
                }
                catch (Exception e)
                {
                    GameLogger crashReport = new GameLogger(e);
                    return false;
                }
            }
        }

        public bool InitializeGraphics()
        {
            try
            {
                pres.Windowed = true;
                pres.SwapEffect = SwapEffect.Discard;
                pres.EnableAutoDepthStencil = true;
                pres.AutoDepthStencilFormat = DepthFormat.D24S8;
                pres.MultiSample = MultiSampleType.None;
                //pres.BackBufferCount = 1;

                //Console.WriteLine(this.Width + " " + this.Height

               // pres.BackBufferWidth = 1280;
                //pres.BackBufferHeight = 960;
                //pres.DeviceWindow = this;
                
                if (!pres.Windowed)
                {
                    pres.BackBufferWidth = 1600;
                    pres.BackBufferHeight = 1200;
                    pres.BackBufferFormat = Format.X8R8G8B8;
                    pres.BackBufferCount = 1;
                    pres.DeviceWindowHandle = this.Handle;
                    pres.PresentFlag = PresentFlag.DiscardDepthStencil;
                }

                pres.PresentationInterval = PresentInterval.One;

                if (debug) logger.WriteLine("Graphics Initialization Completed Successfully after " + texTime.ElapsedMilliseconds + "ms");
                return true;
            }
            catch (Exception e)
            {
                CloseOnException(e);
                return false;
            }
        }

        private void InitializeDevice()
        {
            try
            {
                device = new Microsoft.DirectX.Direct3D.Device(0, Microsoft.DirectX.Direct3D.DeviceType.Hardware, this,
                //device = new Microsoft.DirectX.Direct3D.Device(2, Microsoft.DirectX.Direct3D.DeviceType.Reference, this,
                                                                CreateFlags.HardwareVertexProcessing, pres);
                 
                if (debug) logger.WriteLine("Device Initialization Completed Successfully after " + texTime.ElapsedMilliseconds + "ms");
            }
            catch (Exception e)
            {
                CloseOnException(e);
            }

        }

        private void InitializeMouse()
        {
            try
            {
                mouse = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Mouse);
                mouse.SetCooperativeLevel(this, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive);
                mouse.Acquire();
                if (debug) logger.WriteLine("Mouse Acquisition Completed Successfully after " + texTime.ElapsedMilliseconds + "ms");
            }
            catch (Exception e)
            {
                CloseOnException(e);
            }
        }

        protected void InitializeKeyboard()
        {
            try
            {
                keyb = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Keyboard);
                keyb.SetCooperativeLevel(this, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive);
                keyb.Acquire();
                if (debug) logger.WriteLine("Keyboard Acquisition Completed Successfully after " + texTime.ElapsedMilliseconds + "ms");
            }
            catch (Exception e)
            {
                CloseOnException(e);
            }
        }

        private void InitializeGUI()
        {
            try
            {
                newGUI = new GUIManager();
                guiSprite = new Sprite(device);
                arial14 = new Microsoft.DirectX.Direct3D.Font(device, new System.Drawing.Font("Arial", 14)); 

                ButtonBar guiBar = new ButtonBar(new PointF(0,0));
                newGUI.OpenNewWindow(guiBar);

                if (debug) logger.WriteLine("GUI Initialization Completed Successfully after " + texTime.ElapsedMilliseconds + "ms");
            }
            catch (Exception e)
                {
                CloseOnException(e);
            }
        }


        public void myButtonPress()
        {
            if (!onTheGui)
            {
                if (Focused)
                {
                    KeyboardState state = keyb.GetCurrentKeyboardState();

                    int mult = 1;
                    if (state[Key.LeftShift] || state[Key.RightShift]) mult = 10;
                    if (state[Key.RightControl] || state[Key.LeftControl]) mult = 3;

                    if (state[Key.Escape])
                    {
                        quitting = true;
                    }
                    if (state[Key.W])
                    {
                        myCamera.MoveForward(0.05f * mult);
                    }
                    if (state[Key.S])
                    {
                        myCamera.MoveForward(-0.05f * mult);
                    }
                    if (state[Key.A])
                    {
                        myCamera.Strafe(-0.05f * mult);
                    }
                    if (state[Key.D])
                    {
                        myCamera.Strafe(0.05f * mult);
                    }
                    if (state[Key.Q])
                    {
                        myCamera.UpDown(0.05f * mult);
                    }
                    if (state[Key.Z])
                    {
                        myCamera.UpDown(-0.05f * mult);
                    }
                    if (state[Key.I])
                    {
                        if (device.RenderState.FillMode != FillMode.WireFrame)
                        {
                            device.RenderState.FillMode = FillMode.WireFrame;
                        }
                        else { device.RenderState.FillMode = FillMode.Solid; }
                    }
                    if (state[Key.LeftArrow])
                    {
                        myCamera.AdjustYaw(-0.03f);
                    }

                    if (state[Key.RightArrow])
                    {
                        myCamera.AdjustYaw(0.03f);
                    }

                    if (state[Key.UpArrow])
                    {
                        myCamera.AdjustPitch(0.01f);
                    }

                    if (state[Key.DownArrow])
                    {
                        myCamera.AdjustPitch(-0.01f);
                    }

                }
            }
        }

        public void mouseMove(object sender, MouseEventArgs e)
        {
            //lastMouseEventArgs = e;

            //mouse.Poll();
            //state = mouse.CurrentMouseState;

            //if (TestForGUI(state, e))
            //{

            //}
            //else
            //{
            //    if (landscaper.ActiveTool != LandscapingType.None)
            //    {
            //        if (PickCorner(e, myCamera))
            //        {
            //            byte[] buttons = state.GetMouseButtons();

            //            gameWorld.EditLand(landscaper.MouseHandler(GameGrid.activeCorner, buttons[0] == 128));
            //        }
            //    }
            //}

            //oldCursorLocation = newCursorLocation;
            //newCursorLocation = new Coordinate(e.X, e.Y);
            //myMouseMove(state);
        }

        public void myMouseMove()
        {
            mouse.Poll();
            MouseState state = mouse.CurrentMouseState;
            mouseButtons = state.GetMouseButtons();

            Point topleft = this.PointToClient(new Point(0, 0));

            if (mouseButtons[2] == 128)
            {
                
                float moveX = state.X / 300.00f;

                
                myCamera.RotateAroundLook(moveX);  
            }

            if (mouseButtons[1] == 128)
            {
                float moveY = state.Y / 300.00f;
                float moveX = state.X / 300f;
                myCamera.AdjustYaw(moveX);
                myCamera.AdjustPitch(moveY);
            }

            

            MouseEventArgs mev = new MouseEventArgs(MouseButtons.None, 0, System.Windows.Forms.Cursor.Position.X + topleft.X, System.Windows.Forms.Cursor.Position.Y + topleft.Y, 0);

            if (TestForGUI(state, mev))
            {

            }
            else
            {
                GridPickData data = gameWorld.Scene.PickGrid(mev.Location, myCamera);
                //Text = data.Coord.ToString();
                toolbox.MouseMove(mev.Location, data);
            }
            //else if (GameGrid.activeTile.X != -1)
            //{
            //    byte[] buttons = state.GetMouseButtons();
            //    if(toolbox.GetTool(ToolType.Landscaping).Active)
            //        (toolbox.GetTool(ToolType.Landscaping) as LandscapingTool).MouseHandler(GameGrid.activeVert, buttons[0] == 128);
            //}
        }

        public void myMouseWheel(object sender, MouseEventArgs e)
        {
            //mouse.Poll();
            state = mouse.CurrentMouseState;

            if (!TestForGUI(state, e))
            {
                myCamera.Zoom((float)e.Delta / 30);
            }

        }

        private bool TestForGUI(MouseState state, MouseEventArgs e)
        {
            Point cursor = e.Location;

            byte[] mbuttons = state.GetMouseButtons();

            bool[] buttons = new bool[mbuttons.Length];

            for (int i = 0; i < buttons.Length; i++)
            {
                buttons[i] = (mbuttons[i] == 128);
            }

            return newGUI.MouseHandler(cursor, buttons, e.Delta);
        }

        public void myMouseDown(object sender, MouseEventArgs e)
        {
            //mouse.Poll();
            state = mouse.CurrentMouseState;

            if (TestForGUI(state, e))
            {
            }
            else
            {
                if (e.Button == MouseButtons.Left)
                {
                    GridPickData data = gameWorld.Scene.PickGrid(e.Location, myCamera);

                    toolbox.MouseDown(e.Location, data);
                }
            }

            if (e.Button == MouseButtons.Middle)
            {
                paused = !paused;
            }
        }
            
        public void myMouseUp(object sender, MouseEventArgs e)
        {
            //mouse.Poll();
            state = mouse.CurrentMouseState;

            if (TestForGUI(state, e))
            {
            }
            else
            {
                if (e.Button == MouseButtons.Left)
                {
                    GridPickData data = gameWorld.Scene.PickGrid(e.Location, myCamera);

                    toolbox.MouseUp(e.Location, data);
                }
            }

            if (e.Button == MouseButtons.Middle)
            {
                //paused = false;
            }
        }

        #region Picking
        
        //

        //    Point mouseLoc = mouseEvent.Location;
        //    bool pickFound = false;
        //    

        //    Game.device.Transform.World = Matrix.Identity;

        //    Vector3 rayDirection = GetRayDirection(myCamera, mouseLoc);
        //    Vector3 rayStart = GetRayStart(myCamera);

        

        //private bool PickCorner(MouseEventArgs mouseEvent, AJCamera myCamera)
        //{
        //    Point mouseLoc = mouseEvent.Location;

        //    device.Transform.World = Matrix.Identity;

        //    Vector3 rayDirection = GetRayDirection(myCamera, mouseLoc);
        //    Vector3 rayStart = GetRayStart(myCamera);

        //    gameWorld.Scene.mainGrid.PickCorner(rayStart, rayDirection, myCamera);

        //    if (GameGrid.activeVert.X != -1)
        //    {
        //        return true;
        //    }

        //    return false;
        //}

        //private bool PickSide(MouseEventArgs mouseEvent, AJCamera myCamera)
        //{
        //    // Get most of our placeholders for information ready
        //    Point mouseLoc = mouseEvent.Location;

        //    Vector3 rayStart, rayDirection;
        //    Matrix proj = myCamera.Projection;

        //    // Convert the mouse point into a 3D point
        //    Vector3 v;
        //    v.X = (((2.0f * mouseLoc.X) / device.PresentationParameters.BackBufferWidth) - 1) / proj.M11;
        //    v.Y = -(((2.0f * mouseLoc.Y) / device.PresentationParameters.BackBufferHeight) - 1) / proj.M22;
        //    v.Z = 1.0f;

        //    // Get the inverse of the composite view and world matrix
        //    device.Transform.World = Matrix.Identity;
        //    Matrix m = myCamera.View;
        //    m.Invert();

        //    // Transform the screen space pick ray into 3D space
        //    rayDirection.X = v.X * m.M11 + v.Y * m.M21 + v.Z * m.M31;
        //    rayDirection.Y = v.X * m.M12 + v.Y * m.M22 + v.Z * m.M32;
        //    rayDirection.Z = v.X * m.M13 + v.Y * m.M23 + v.Z * m.M33;

        //    rayStart.X = m.M41;
        //    rayStart.Y = m.M42;
        //    rayStart.Z = m.M43;

        //    gameWorld.Scene.mainGrid.PickSide(rayStart, rayDirection, myCamera);

        //    if (GameGrid.activeSide != RotateType.Invalid)
        //    {
        //        return true;
        //    }

        //    return false;
        //} 

        #endregion

        public void Render()
        {
            if (device == null)
                return;

            try
            {
                device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0F, 0);

                device.BeginScene();
                
                myButtonPress();

                myMouseMove();
                SetupCamera();

                gameWorld.Update();

                gameWorld.Scene.Render(myCamera);

                guiSprite.Begin(SpriteFlags.DoNotModifyRenderState | SpriteFlags.AlphaBlend);
                device.RenderState.CullMode = Cull.None;

                newGUI.Render();

                guiSprite.End();

                device.EndScene();

                device.Present();
            }
            catch (Exception e)
            {
                GameLogger crashReport = new GameLogger(e);
                Environment.Exit(1);
            }
        }

        protected void SetupCamera()
        {
            device.Transform.World = Matrix.Identity;
            device.Transform.View = myCamera.View;
            device.Transform.Projection = myCamera.Projection;
        }

        public World World
        {
            get { return gameWorld; }
        }

        public int PlayerNumber
        {
            get { return playerNumber; }
        }

        #region Game Initialisation
        public void InitializeGame(int arg)
        {
            try
            {

                int xlength = arg;
                int zlength = arg;

                gameWorld = new World(xlength, zlength);
                playerNumber = gameWorld.CreateNewCompany();

                toolbox.ChangeToolStatus(ToolType.VehicleSelect, true);
                Game.toolbox.ChangeToolStatus(ToolType.StationSelect, true);
                (Game.toolbox.GetTool(ToolType.StationSelect) as StationSelectTool).OpenWindows = true;

                Mesh sphere = Mesh.Sphere(device, 0.5f, 10, 10);
                int[] adjacency = new int[sphere.NumberFaces * 3];
                ExtendedMaterial[] mats = new ExtendedMaterial[0];
                sphere.GenerateAdjacency(0f, adjacency);
                sphere.Save("sphere2.x", adjacency, mats, XFileFormat.Text);

                Random rng = new Random();

                int firstX = rng.Next(xlength - 2);
                int firstZ = rng.Next(zlength - 1);

                int secondX = rng.Next(xlength - 2);
                int secondZ = rng.Next(zlength - 1);

                int thirdX = rng.Next(xlength - 2);
                int thirdZ = rng.Next(zlength - 1);

                Company comp = gameWorld.GetCompany(playerNumber);

                TTDotNet.Engine.GUI.ScreenStatusBar statusBar = new TTDotNet.Engine.GUI.ScreenStatusBar(comp, new PointF(0, 0));
                newGUI.OpenNewWindow(statusBar);

                int interval = 36;

                gameWorld.CreateNewTown("Townsville", new Coordinate(10, 10));

                int nextInd = 0;

                for (int x = interval / 2; x < arg; x += interval)
                {
                    for (int z = interval / 2; z < arg; z += interval)
                    {
                        nextInd = rng.Next(5);
                        gameWorld.Towns[0].AddNewIndustry(new Coordinate((x - interval / 2) + 2, (z - interval / 2) + 2), RotateType.Zero, (IndustryType)nextInd);

                        (toolbox.GetTool(ToolType.RoadDepot) as RoadDepotTool).BuildRoadDepot(new DDDCoordinate(x, 0, z));
                        (toolbox.GetTool(ToolType.BusStation) as BusStationTool).BuildBusStation(new Coordinate(x - interval / 2, z - interval / 2));

                        
                    }
                }

                //AJMeshH newMesh = new AJMeshH("data/meshes/Vehicles/Road/newbus.x", ObjectType.Vehicle);

                //InstancedMesh iMesh = meshManager.CreateMesh("data/meshes/Vehicles/Road/newbus.x", new Vector3(1, 0, 1), Vector3.Empty, ObjectType.Vehicle);

                //InstancedMesh iMesh2 = meshManager.CreateMesh("data/meshes/Vehicles/Road/newbus.x", new Vector3(2, 0, 2), Vector3.Empty, ObjectType.Vehicle);

                //Coordinate a = new Coordinate(firstX, firstZ);
                //Coordinate b = new Coordinate(secondX, secondZ);
                //Coordinate d = new Coordinate(thirdX, thirdZ);

                //BusStation source = new BusStation(comp, "Bus Station A", a, RotateType.Ninety);
                //BusStation dest = new BusStation(comp, "Bus Station B", b, RotateType.None);
                //BusStation other = new BusStation(comp, "Bus Station C", d, RotateType.None);

                

                //myVehc.AddOrder(new Order(dest, OrderType.None));
                //myVehc.AddOrder(new Order(other, OrderType.None));
                //myVehc.AddOrder(new Order(source, OrderType.None));

                //Vehicle vehc2 = new RoadVehicle("MPS Regal Bus 2", roadVehicles[0], gameWorld.GetCompany(playerNumber), new DateTime(), new Vector3(secondX, 0, secondZ + 0.25f));
                //vehc2.RotateBy(new Vector3(0, 90, 0));

                //gameWorld.AddVehicle(0, vehc2);

                //vehc2.AddOrder(new Order(other, OrderType.None));
                //vehc2.AddOrder(new Order(dest, OrderType.None));
                //vehc2.AddOrder(new Order(source, OrderType.None));

                //gameWorld.CreateNewTown("Townsville", new Coordinate(10, 10));

                //gameWorld.Towns[0].AddNewIndustry(new Coordinate(12, 6), RotateType.Zero, IndustryType.Coal_Mine);
                //gameWorld.Towns[0].AddNewIndustry(new Coordinate(36, 33), RotateType.Zero, IndustryType.Power_Station);
                //gameWorld.Towns[0].AddNewIndustry(new Coordinate(15, 15), RotateType.Zero, IndustryType.Forest);
                //gameWorld.Towns[0].AddNewIndustry(new Coordinate(6, 33), RotateType.Zero, IndustryType.Iron_Ore_Mine);
                //gameWorld.Towns[0].AddNewIndustry(new Coordinate(42, 12), RotateType.Zero, IndustryType.Sawmill);
                

                //myTown.AddNewIndustry(new Coordinate(7, 7), RotateType.None, IndustryType.Iron_Ore_Mine);
                //myTown.AddNewIndustry(new Coordinate(1, 10), RotateType.None, IndustryType.Forest);
                //myTown.AddNewIndustry(new Coordinate(7, 2), RotateType.None, IndustryType.Power_Station);


                //Town myTown2 = new Town(new Coordinate(11, 11));
                //myTown2.AddNewIndustry(new Coordinate(11, 11), IndustryType.Coal_Mine);

                


                if (debug) logger.WriteLine("World Initialization Completed Successfully after " + texTime.ElapsedMilliseconds + "ms");

            }
            catch (Exception e)
            {
                CloseOnException(e);
            }

        }
        #endregion

        private void InitializeComponent()
        {
            try
            {
                this.ClientSize = new System.Drawing.Size(1024, 768);
                
                
                if (debug) logger.WriteLine("InitializeComponent Completed Successfully after " + texTime.ElapsedMilliseconds + "ms");
            }
            catch (Exception e)
            {
                CloseOnException(e);
            }

        }

        protected override void OnLocationChanged(EventArgs e)
        {
            Render();
        }

        public static void CloseOnException(Exception e) {
            if (debug) logger.WriteException(e);
            System.Windows.Forms.MessageBox.Show("Error - Please check last GameLog.");
            Environment.Exit(1);
        }
        
    }

    public class NativeMethods
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct Message
        {
            public IntPtr hWnd;
            public WindowMessage msg;
            public IntPtr wParam;
            public IntPtr lParam;
            public uint time;
            public System.Drawing.Point p;
        }

        [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool PeekMessage(out Message msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);
    }

    public enum WindowMessage : uint
    {
        // Misc messages
        Destroy = 0x0002,
        Close = 0x0010,
        Quit = 0x0012,
        Paint = 0x000F,
        SetCursor = 0x0020,
        ActivateApplication = 0x001C,
        EnterMenuLoop = 0x0211,
        ExitMenuLoop = 0x0212,
        NonClientHitTest = 0x0084,
        PowerBroadcast = 0x0218,
        SystemCommand = 0x0112,
        GetMinMax = 0x0024,

        // Keyboard messages
        KeyDown = 0x0100,
        KeyUp = 0x0101,
        Character = 0x0102,
        SystemKeyDown = 0x0104,
        SystemKeyUp = 0x0105,
        SystemCharacter = 0x0106,

        // Mouse messages
        MouseMove = 0x0200,
        LeftButtonDown = 0x0201,
        LeftButtonUp = 0x0202,
        LeftButtonDoubleClick = 0x0203,
        RightButtonDown = 0x0204,
        RightButtonUp = 0x0205,
        RightButtonDoubleClick = 0x0206,
        MiddleButtonDown = 0x0207,
        MiddleButtonUp = 0x0208,
        MiddleButtonDoubleClick = 0x0209,
        MouseWheel = 0x020a,
        XButtonDown = 0x020B,
        XButtonUp = 0x020c,
        XButtonDoubleClick = 0x020d,
        MouseFirst = LeftButtonDown, // Skip mouse move, it happens a lot and there is another message for that
        MouseLast = XButtonDoubleClick,

        // Sizing
        EnterSizeMove = 0x0231,
        ExitSizeMove = 0x0232,
        Size = 0x0005,

    }

}
